/*
 * Copyright 2011, 2012 Chris Banes.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package uk.co.senab2.photoview2.gestures;

import ohos.agp.components.VelocityDetector;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

import uk.co.senab2.photoview2.log.LogManager;

/**
 * CupcakeGestureDetector.
 *
 * @author author
 * @version version
 */
public class CupcakeGestureDetector implements GestureDetector {
    /**
     * MINIMUM_FLING_VELOCITY.
     */
    public static final int MINIMUM_FLING_VELOCITY = 50;
    /**
     * MINIMUM_FLING_VELOCITY.
     */
    public static final int TOUCH_SLOP = 8;
    /**
     * OnGestureListener.
     */
    protected OnGestureListener mListener;
    private static final String LOG_TAG = "CupcakeGestureDetector";
    float mLastTouchX;
    float mLastTouchY;
    final float mTouchSlop;
    final float mMinimumVelocity;

    @Override
    public void setOnGestureListener(OnGestureListener listener) {
        this.mListener = listener;
    }

    public CupcakeGestureDetector(Context context) {
        mMinimumVelocity = MINIMUM_FLING_VELOCITY;
        mTouchSlop = TOUCH_SLOP;
    }

    private VelocityDetector mVelocityTracker;
    private boolean mIsDragging;

    float getActiveX(TouchEvent ev) {
        return ev.getPointerPosition(ev.getIndex()).getX();
    }

    float getActiveY(TouchEvent ev) {
        return ev.getPointerPosition(ev.getIndex()).getY();
    }

    @Override
    public boolean isScaling() {
        return false;
    }

    @Override
    public boolean isDragging() {
        return mIsDragging;
    }

    private void downAction(TouchEvent ev) {
        mVelocityTracker = VelocityDetector.obtainInstance();
        if (null != mVelocityTracker) {
            mVelocityTracker.addEvent(ev);
        } else {
            LogManager.getLogger().i(LOG_TAG, "Velocity tracker is null");
        }

        mLastTouchX = getActiveX(ev);
        mLastTouchY = getActiveY(ev);
        mIsDragging = false;
    }

    private void moveAction(TouchEvent ev) {
        final float x = getActiveX(ev);
        final float y = getActiveY(ev);
        final float dx = x - mLastTouchX, dy = y - mLastTouchY;

        if (!mIsDragging) {
            // Use Pythagoras to see if drag length is larger than
            // touch slop
            mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
        }
        if (mIsDragging) {
            mListener.onDrag(dx, dy);
            mLastTouchX = x;
            mLastTouchY = y;

            if (null != mVelocityTracker) {
                mVelocityTracker.addEvent(ev);
            }
        }
    }

    private void upAction(TouchEvent ev) {
        if (mIsDragging) {
            if (null != mVelocityTracker) {
                mLastTouchX = getActiveX(ev);
                mLastTouchY = getActiveY(ev);
                // Compute velocity within the last 1000ms
                mVelocityTracker.addEvent(ev);
                mVelocityTracker.calculateCurrentVelocity(1000);
                final float vX = mVelocityTracker.getHorizontalVelocity(), vY = mVelocityTracker
                        .getVerticalVelocity();
                // If the velocity is greater than minVelocity, call
                // listener
                if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) {
                    mListener.onFling(mLastTouchX, mLastTouchY, -vX,
                            -vY);
                }
            }
        }
        // Recycle Velocity Tracker
        if (null != mVelocityTracker) {
            mVelocityTracker.clear();
            mVelocityTracker = null;
        }
    }


    @Override
    public boolean onTouchEvent(TouchEvent ev) {
        switch (ev.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN: {
                downAction(ev);
                break;
            }

            case TouchEvent.POINT_MOVE: {
                moveAction(ev);
                break;
            }

            case TouchEvent.CANCEL: {
                // Recycle Velocity Tracker
                if (null != mVelocityTracker) {
                    mVelocityTracker.clear();
                    mVelocityTracker = null;
                }
                break;
            }

            case TouchEvent.PRIMARY_POINT_UP: {
                upAction(ev);
                break;
            }
        }

        return true;
    }
}
